home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Collections: Taifun
/
Taifun 054 (1988-05-15)(Ossowski, Stefan)(DE)(PD).zip
/
Taifun 054 (1988-05-15)(Ossowski, Stefan)(DE)(PD).adf
/
MRBackup
/
MRBackup2.0
/
FormatDisk.c
< prev
next >
Wrap
C/C++ Source or Header
|
1988-04-09
|
10KB
|
374 lines
/* Format a floppy disk (880k drive).
* Author: Mark R. Rinfret
* Date: 06/28/87
* Description:
* This set of routines may be incorporated into a program which
* has need of formatting a floppy disk. I wrote it to support my
* hard disk backup utility.
*
* History: (most recent change first)
*
* 12/08/87 -MRR- My floppy drive (at least) will occaisionally "hang"
* during formatting. I don't know what the source of
* the problem is, but for now I've added a timer and
* switched to a SendIO/Wait combo to handle this.
*
* 08/26/87 -MRR- Modified FormatDisk to delay 5 seconds after
* uninhibiting the drive. This should give enough time
* for the validator to do its thing and prevent the
* "Insert disk..." requester from rearing its ugly head
* if the application attempts to access the disk as
* soon as we return.
*/
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/io.h>
#include <exec/devices.h>
#include <devices/trackdisk.h>
#include <libraries/dosextens.h>
#include ":src/lib/AmigaFunctions.h"
#include ":src/lib/Timer.h"
extern struct IOExtTD *CreateExtIO();
static int CkIOErr();
#define MAX_NAME 30L
#define TD_WRITE CMD_WRITE
#define TRACKSIZE NUMSECS * TD_SECTOR
/* Format a floppy disk - hardwired for the 3.5" 880k floppy drives.
* Called with:
* drivename: device name (DF0, etc.)
* name: new volume name
* Returns:
* Zero on success, 1 on failure
* Note:
* This routine does not currently perform a verification, as
* recommended by the RKM. Perhaps later...
* I also discovered that there's some erroneous crap in
* "The Amiga Programmer's Workbook, Vol. II", by
* Eugene P. Mortimore. On page 339, he states that only 512
* bytes of track data are required for formatting. The RKM
* correctly states that a "track's worth of data" is required.
* It took some playing with DiskEd to discover this error.
*/
int
FormatDisk(drivename,name)
char *drivename; char *name;
{
long checkSum;
char *dosID = "DOS";
long dosWord = 0;
short error;
long diskBit, timerBit;
struct MsgPort *diskPort = NULL;
struct IOExtTD *diskRequest = NULL;
ULONG diskChangeCount;
USHORT retries, status = 0, i, timeout, track;
long signals; /* signal bits from Wait() */
struct timerequest *timeRequest; /* timeout timer request */
int unit;
char *volname;
char *diskBuffer;
ULONG *diskBlock; /* alias for diskBuffer, ULONG type */
if (strlen(name) >= MAX_NAME) {
#ifdef DEBUG
printf("Disk name is too long!\n");
#endif
status = ERROR_INVALID_COMPONENT_NAME;
goto cleanup;
}
if ((unit = (drivename[2]-'0')) < 0 || unit >= NUMUNITS) {
#ifdef DEBUG
printf("FormatDisk: invalid drive specification!\n");
#endif
status = ERROR_INVALID_COMPONENT_NAME;
goto cleanup;
}
if (!(diskBuffer =
AllocMem((long) TRACKSIZE, MEMF_PUBLIC | MEMF_CHIP))) {
status = ERROR_NO_FREE_STORE;
goto cleanup;
}
timeRequest = CreateTimer(0); /* create uHERZ timer */
if (timeRequest == NULL) {
status = ERROR_NO_FREE_STORE; /* would IoError be valid? */
goto cleanup;
}
/* Store DOS "magic word" in disk block to be written during
* formatting.
*/
diskBlock = (ULONG *) diskBuffer;/* we'll need this later */
for (i = 0; i < 3; ++i)
dosWord = (dosWord << 8) | dosID[i];
dosWord = dosWord << 8;
#ifdef DEBUG
printf("dosWord is %lx\n",dosWord);
#endif
for (i = 0; i < TRACKSIZE / 4; ++i)
diskBlock[i] = (dosWord | (long) (i & 0xff));
if ((diskPort = CreatePort(0L, 0L)) == NULL) {
#ifdef DEBUG
printf("FormatDisk can't create port!\n");
#endif
status = 1; /* is there a better error code? */
goto cleanup;
}
if (!(diskRequest = (struct IOExtTD *)
CreateExtIO(diskPort, (long) sizeof(struct IOExtTD)))) {
status = 1;
goto cleanup;
}
if (status = OpenDevice(TD_NAME, (long) unit, diskRequest, 0L)) {
#ifdef DEBUG
printf("FormatDisk: OpenDevice error: %d\n",error);
#endif
goto cleanup;
}
if (status = Inhibit(drivename, 1)) {
#ifdef DEBUG
printf("FormatDisk: unable to inhibit drive!\n");
#endif
goto cleanup;
}
/* Get the current disk change count. This allows the trackdisk
* driver to detect unwanted disk changes later on.
*/
diskRequest->iotd_Req.io_Command = TD_CHANGENUM;
DoIO(diskRequest);
/* Save a copy of the disk change count. */
diskChangeCount = diskRequest->iotd_Req.io_Actual;
#ifdef DEBUG
printf("Current disk change count is %ld\n", diskChangeCount);
#endif
/* Format the disk, one track at a time. This operation seems
* susceptible to timing out (infrequently) on my system, so we'll
* use a combination of SendIO and Wait, rather than DoIO.
*/
diskBit =
1L << diskRequest->iotd_Req.io_Message.mn_ReplyPort->mp_SigBit;
timerBit =
1L << timeRequest->tr_node.io_Message.mn_ReplyPort->mp_SigBit;
#ifdef DEBUG
printf("diskBit => %08lx, timerBit => %08lx\n",
diskBit, timerBit);
#endif
for (track = 0; track < NUMTRACKS; ++track) {
retries = 0;
retry:
diskRequest->iotd_Req.io_Command = TD_FORMAT;
diskRequest->iotd_Req.io_Flags = 0;
diskRequest->iotd_Req.io_Data = (APTR) diskBuffer;
diskRequest->iotd_Count = diskChangeCount;
diskRequest->iotd_Req.io_Length = NUMSECS * TD_SECTOR;
diskRequest->iotd_Req.io_Offset = track * NUMSECS * TD_SECTOR;
SendIO(diskRequest);
StartTimer(timeRequest, 5L, 0L); /* Start 5 second disk timer. */
#ifdef DEBUG
if (timeRequest->tr_node.io_Error) {
printf("Error on StartTimer: %d\n",
timeRequest->tr_node.io_Error);
}
#endif
while (TRUE) {
timeout = 0;
signals = Wait(diskBit | timerBit);
if (signals & timerBit) {
if (CheckIO(timeRequest)) { /* timer I/O complete? */
WaitIO(timeRequest); /* complete timer processing */
AbortIO(diskRequest); /* kill disk I/O */
timeout = 1;
#ifdef DEBUG
puts("--TIMEOUT--");
#endif
break;
}
}
if (signals & diskBit) { /* Did disk complete? */
if (CheckIO(diskRequest)) {
WaitIO(diskRequest); /* complete disk processing */
StopTimer(timeRequest);
break;
}
}
} /* end while(TRUE) */
/* Retry a timeout 3 times before giving up. */
if (timeout && (++retries < 4) ) goto retry;
if (status = CkIOErr(diskRequest,"Formatting error")) {
#ifdef DEBUG
printf(" Track: %d\n",track);
#endif
goto cleanup;
}
}
/* Now comes some real KLUDGING. Fill in the root block and the
* first hash block. The information for this was gathered from
* the "AmigaDos Technical Reference Manual" and some sleuthing
* with DiskEd.
*/
for (i = 0; i < 128; ++i)
diskBlock[i] = 0;
diskBlock[0] = 2; /* T.SHORT (type) */
diskBlock[3] = 128 - 56; /* hashtable size */
diskBlock[78] = 0xffffffff; /* BMFLAG */
diskBlock[79] = 881; /* first bitmap block */
DateStamp(&diskBlock[105]); /* volume last altered date/time */
DateStamp(&diskBlock[121]); /* volume creation date/time */
volname = (char *) &diskBlock[108];
/* convert input name to BSTR */
*volname = strlen(name);
for (i = 0; i < *volname; ++i)
*(volname + 1 + i) = *(name + i);
diskBlock[127] = 1; /* ST.ROOT (secondary type) */
checkSum = 0;
for (i = 0; i < 128; ++i)
checkSum += diskBlock[i];
diskBlock[5] = - checkSum;
/* Write the root block out to the disk. */
diskRequest->iotd_Req.io_Command = TD_WRITE;
diskRequest->iotd_Req.io_Length = TD_SECTOR;
diskRequest->iotd_Req.io_Offset = TD_SECTOR * 880L;
DoIO(diskRequest);
if (status = CkIOErr(diskRequest, "Error writing root block")) {
goto cleanup;
}
/* Write the first bitmap block. */
for (i = 0; i < 56; ++i)
diskBlock[i] = 0xffffffff;
for (i = 56; i < 128; ++i)
diskBlock[i] = 0;
diskBlock[0] = 0xc000c037; /* hint: x37 = 55 (last word of map?) */
diskBlock[28] = 0xffff3fff; /* blocks 880, 881 used */
diskBlock[55] = 0x3fffffff; /* blocks 1760, 1761 used? */
diskRequest->iotd_Req.io_Length = TD_SECTOR;
diskRequest->iotd_Req.io_Offset = 881L * TD_SECTOR;
DoIO(diskRequest); /* write out the bitmap */
if (status = CkIOErr(diskRequest, "Error writing bitmap")) {
goto cleanup;
}
diskRequest->iotd_Req.io_Command = ETD_UPDATE;
diskRequest->iotd_Req.io_Flags = 0;
DoIO(diskRequest);
/* Turn the disk motor off. */
diskRequest->iotd_Req.io_Command = TD_MOTOR;
diskRequest->iotd_Req.io_Length = 0;
DoIO(diskRequest);
Inhibit(drivename, 0); /* enable disk validator */
Delay(3L * TICKS_PER_SECOND); /* Give it a chance */
cleanup:
CloseDevice(diskRequest);
if (diskBuffer) FreeMem(diskBuffer, (long) TRACKSIZE);
if (diskRequest) DeleteExtIO(diskRequest, (long) sizeof(*diskRequest));
if (diskPort) DeletePort(diskPort);
if (timeRequest) DeleteTimer(timeRequest);
return status;
}
/* Check the disk request block for an error code. If an error
* occurred, print the argument string.
* Called with:
* req: pointer to I/O request structure
* msg: error message string
* Returns:
* error code from request structure
*/
static int CkIOErr(req, msg)
struct IOStdReq *req; char *msg;
{
register int code;
if (code = req->io_Error) {
#ifdef DEBUG
printf("%s, code: %d\n",msg,code);
#endif
}
return code;
}
#ifdef DEBUG
main(argc, argv)
int argc; char *argv[];
{
char *diskname;
char *volname;
int unit;
if (argc < 3)
volname = "GoodJob!";
else
volname = argv[2];
if (argc < 2)
diskname = "DF1:";
else {
diskname = argv[1];
if (strlen(diskname) != 4 ||
(strncmp(diskname,"df",2) && strncmp(diskname,"DF",2))) {
bad_drive:
printf("Drive name may only be df0: through df3:!\n");
exit(1);
}
if ((unit = (diskname[2] - '0')) < 0 || unit > 3)
goto bad_drive;
}
printf("Insert disk in %s, then hit return\n",diskname);
while (getchar() != '\n');
if (FormatDisk(diskname,volname))
printf("FormatDisk failed\n");
else {
printf("FormatDisk succeeded\n");
}
}
#endif